home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / common / readable.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  27KB  |  859 lines

  1.  
  2. /* This file contains code relevant to the BOOKS hack -- designed
  3.  * to allow randomly occuring messages in non-magical texts.
  4.  */
  5.  
  6. /* laid down initial file - dec 1995. -b.t. thomas@astro.psu.edu */
  7.  
  8. #include <global.h>
  9. #include <read.h>
  10. #include <book.h>
  11. #include <living.h>
  12. #include <spells.h>
  13.  
  14. /* This flag is useful to see what kind of output messages are created */
  15.  
  16. /* #define BOOK_MSG_DEBUG */ 
  17.  
  18.  
  19. /* init_readable() - initialize linked lists utilized by 
  20.  * message functions in tailor_readable_ob() */
  21.  
  22. void init_readable( void ) {
  23.   static int did_this;
  24.  
  25.   if(!did_this) did_this=1; 
  26.   else return;
  27.  
  28.   fprintf(logfile,"\nInitializing reading data...");
  29.   init_msgfile();
  30.   init_mon_info();
  31.  
  32. }
  33.  
  34. /* tailor_readable_ob()- The main routine. This chooses a random 
  35.  * message to put in given readable object (type==BOOK) which will 
  36.  * be referred hereafter as a 'book'. We use the book level to de- 
  37.  * termine the value of the information we will insert. Higher 
  38.  * values mean the book will (generally) have better/more info. 
  39.  * See individual cases as to how this will be utilized.
  40.  * "Book" name/content length are based on the weight of the 
  41.  * document. If the value of msg_type is negative, we will randomly
  42.  * choose the kind of message to generate. 
  43.  * -b.t. thomas@astro.psu.edu
  44.  */
  45.  
  46. void tailor_readable_ob (object *book, int msg_type) {
  47.   char msgbuf[BOOK_BUF];
  48.   int level=book->level?(RANDOM()%book->level)+1:1;
  49.   int book_buf_size;
  50.   
  51.   /* safety */
  52.   if(book->type!=BOOK) return;
  53.  
  54.   /* lets give the "book" a new name, which may be a compound word */
  55.   change_book_name(book);
  56.  
  57.   if(level<=0) return; /* if no level no point in doing any more... */
  58.  
  59.   book_buf_size = BOOKSIZE(book);
  60.  
  61.     /* ...but lets not exceed the actual max buffer!... */
  62.   if(book_buf_size>BOOK_BUF) book_buf_size = BOOK_BUF;
  63.  
  64.    /* &&& The message switch &&& */
  65.    /* Below all of the possible types of messages in the "book"s.
  66.     * if you add another case, make sure all are reachable by the 
  67.     * random number generator */
  68.  
  69.   switch(msg_type>0?msg_type:(RANDOM()%6+1)) {
  70.         case 1: /* monster attrib */
  71.           strcpy(msgbuf, mon_info_msg(level,book_buf_size));
  72.           break;
  73.         case 2: /* artifact attrib */
  74.           strcpy(msgbuf, artifact_msg(level,book_buf_size));
  75.           break;
  76.         case 3: /* grouping spells/prayers by path */
  77.           strcpy(msgbuf, spellpath_msg(level,book_buf_size));
  78.           break;
  79.         case 4: /* describe an alchemy formula */
  80. #ifdef ALCHEMY
  81.           strcpy(msgbuf, formula_msg(level,book_buf_size));
  82. #else
  83.           strcpy(msgbuf, msgfile_msg(level,book_buf_size));
  84. #endif
  85.           break;
  86.         case 5: /* bits of information about a god */
  87. #ifdef MULTIPLE_GODS 
  88.           strcpy(msgbuf, god_info_msg(level,book_buf_size));
  89. #else
  90.           strcpy(msgbuf, msgfile_msg(level,book_buf_size));
  91. #endif 
  92.           break;
  93.         case 6: /* use info list in lib/ */
  94.         default:
  95.           strcpy(msgbuf, msgfile_msg(level,book_buf_size));
  96.           break;
  97.   }
  98.  
  99.   strcat(msgbuf,"\n"); /* safety -- we get ugly map saves/crashes w/o this */ 
  100.   if(strlen(msgbuf)>1) {
  101.       if(book->msg) free_string(book->msg);
  102.     book->msg=add_string(msgbuf);
  103.   }
  104. }
  105.  
  106. /* change_book_name() - give a new, fancier name to generated 
  107.  * objects of type BOOK and SPELLBOOK.
  108.  */
  109.  
  110. void change_book_name (object *book) {
  111.   int nbr = sizeof(book_descrpt)/sizeof(char *);
  112.   char name[MAX_BUF];
  113.  
  114.  /* build up a new name buffer in 2 steps */
  115.  
  116.    /* first the name of the book. */
  117.   switch(book->type) {
  118.      case BOOK:  /* Name based on weight */
  119.         if(book->weight>2000) {
  120.            nbr = sizeof(heavy_book_name)/sizeof(char *);
  121.            strcpy(name,heavy_book_name[RANDOM()%nbr]);
  122.         } else if(book->weight<2001) {
  123.            nbr = sizeof(light_book_name)/sizeof(char *);
  124.            strcpy(name,light_book_name[RANDOM()%nbr]);
  125.         }
  126.         /* lets give the book an author */
  127.         if(!book->title&&(strlen(name)<20)&&!(RANDOM()%2))
  128.           add_author(book);
  129.     break;
  130.       case SPELLBOOK: /* depends on mage/clerical */
  131.     if(!strcmp(book->arch->name,"cleric_book")) { 
  132.            nbr = sizeof(priest_book_name)/sizeof(char *);
  133.            strcpy(name,priest_book_name[RANDOM()%nbr]);
  134.     } else {
  135.            nbr = sizeof(mage_book_name)/sizeof(char *);
  136.            strcpy(name,mage_book_name[RANDOM()%nbr]);
  137.     }
  138.         break;
  139.       default:
  140.         LOG(llevError,"change_book_name() called w/ illegal obj type.\n"); 
  141.     return;
  142.   }
  143.  
  144.    /* second, sometimes we give a book description */
  145.   if(!RANDOM()%3) sprintf(name,"%s %s",book_descrpt[RANDOM()%nbr],name);
  146.  
  147.   if(book->name) free_string(book->name);
  148.   book->name = add_string(name);
  149.   
  150. }
  151.  
  152. /* add_book_author() */
  153.  
  154. void add_author (object *op) {
  155.   char name[MAX_BUF];
  156.   int nbr = sizeof(book_author)/sizeof(char *); 
  157.  
  158.   sprintf(name,"of %s",book_author[RANDOM()%nbr]);
  159.   op->title=add_string(name);
  160. }
  161.  
  162. /* msgfile_msg() - generate a message drawn randomly from a 
  163.  * file in lib/. Level currently has no effect on the message
  164.  * which is returned. 
  165.  */
  166.  
  167. char * msgfile_msg (int level, int booksize) {
  168.   static char retbuf[BOOK_BUF];
  169.   int i,msgnum;
  170.   linked_char *msg=NULL;
  171.  
  172.     /* get a random message for the 'book' from linked list */
  173.   if(nrofmsg>1) {
  174.      msg = first_msg;
  175.      msgnum=RANDOM()%nrofmsg; 
  176.      for(i=0;msg&&i<nrofmsg&&i!=msgnum;i++)
  177.     msg=msg->next; 
  178.   }
  179.  
  180.   if(msg&&!book_overflow(retbuf,msg->name,booksize)) 
  181.      strcpy(retbuf,msg->name);
  182.   else 
  183.      sprintf(retbuf,"\n <undecipherable text>");
  184.  
  185. #ifdef BOOK_MSG_DEBUG
  186.   LOG(llevDebug,"\n info_list_msg() created strng: %d\n",strlen(retbuf));
  187.   fprintf(logfile," MADE THIS:\n%s\n",retbuf);
  188. #endif
  189.  
  190.   return retbuf;
  191. }
  192.  
  193. /* init_msgfile() - if not called before, initialize the info list */
  194.  
  195. void init_msgfile ( void ) {
  196.   FILE *fp;
  197.   char buf[MAX_BUF], msgbuf[HUGE_BUF], fname[MAX_BUF], *cp;
  198.   int comp;
  199.   static int did_init_msgfile;
  200.  
  201.   if(did_init_msgfile) return;
  202.   did_init_msgfile=1;
  203.  
  204.   sprintf(fname, "%s/messages", LibDir);
  205.  
  206.   if ((fp = open_and_uncompress(fname, 0, &comp)) != NULL) { 
  207.      linked_char *tmp=NULL;
  208.      while (fgets(buf, MAX_BUF, fp)!=NULL) {
  209.         if (*buf=='#') continue; 
  210.         if((cp=strchr(buf,'\n'))!=NULL) *cp='\0';
  211.         cp=buf;
  212.         while(*cp==' ') /* Skip blanks */
  213.           cp++;
  214.         if(!strncmp(cp, "ENDMSG", 6)) {
  215.         if(strlen(msgbuf)>BOOK_BUF) {
  216.         LOG(llevDebug,"Warning: this string exceeded max book buf size:");
  217.         LOG(llevDebug,"  %s",msgbuf);
  218.         }
  219.             tmp->name = add_string(msgbuf);
  220.             tmp->next = first_msg;
  221.             first_msg = tmp;
  222.             nrofmsg++; continue;
  223.         }
  224.     else if(!strncmp(cp, "MSG", 3)) { 
  225.             tmp = (linked_char*) malloc(sizeof(linked_char));
  226.         strcpy(msgbuf," "); /* reset msgbuf for new message */ 
  227.         continue;
  228.         } else if(!buf_overflow(msgbuf,cp,HUGE_BUF-1)) { 
  229.         strcat(msgbuf,cp); strcat(msgbuf,"\n");
  230.     }
  231.      }   
  232.      close_and_delete(fp, comp);
  233.   }
  234.  
  235. #ifdef BOOK_MSG_DEBUG
  236.     LOG(llevDebug,"\ninit_info_listfile() got %d messages.\n",nrofmsg);
  237. #endif    
  238.  
  239. #ifdef ALCHEMY
  240.  
  241. /* formula_msg() - generate a message detailing the properties
  242.  * of a randomly selected alchemical formula.
  243.  */
  244.  
  245. char * formula_msg (int level, int booksize) {
  246.   static char retbuf[BOOK_BUF];
  247.   recipelist *fl;
  248.   recipe *formula=NULL;
  249.   int chance;
  250.   
  251.   /* the higher the book level, the more complex (ie number of
  252.    * ingredients) the formula can be. 
  253.    */
  254.   fl = get_formulalist(((RANDOM()%level)/3)+1);
  255.  
  256.   if(!fl) fl=get_formulalist(1); /* safety */
  257.     
  258.   if(fl->total_chance==0) { 
  259.       strcpy(retbuf,"\n <undecipherable message> \n");
  260.     return retbuf; 
  261.   } 
  262.  
  263.   /* get a random formula, weighted by its bookchance */
  264.   chance = RANDOM()%fl->total_chance;
  265.   for(formula=fl->items;formula!=NULL;formula=formula->next) { 
  266.     chance -= formula->chance;
  267.     if(chance<=0) break;
  268.   } 
  269.  
  270.   /* preamble */
  271.   strcpy(retbuf,"Herein is described an alchemical proceedure: \n");
  272.  
  273.    /* looks like a formula was found. Base the amount
  274.     * of information on the booklevel and the spellevel
  275.     * of the formula. */ 
  276.   if(formula) { 
  277.       char *op_name=NULL;
  278.     archetype *at;
  279.     int nindex=nstrtok(formula->arch_name,",");
  280.  
  281.     /* construct name of object to be made*/
  282.     if(nindex>1) {
  283.        int rnum = RANDOM()%nindex;
  284.            op_name = strtok(formula->arch_name,",");  
  285.        while(rnum) { op_name = strtok(NULL,","); rnum--; }
  286.     } else 
  287.        op_name = formula->arch_name;  
  288.     if((at=find_archetype(op_name))!=(archetype *)NULL)
  289.        op_name = at->clone.name;
  290.     else 
  291.        LOG(llevError,"formula_msg() can't find arch %s for formula.",
  292.          op_name); 
  293.     /* item name */
  294.     if(strcmp(formula->title,"NONE"))
  295.        sprintf(retbuf,"%sThe %s of %s",retbuf,op_name,formula->title);
  296.     else {
  297.        sprintf(retbuf,"%sThe %s",retbuf,op_name);
  298.       if(at->clone.title) {
  299.           strcat(retbuf," ");
  300.           strcat(retbuf,at->clone.title);
  301.       }
  302.         }
  303.       /* ingredients to make it */
  304.         if (formula->ingred !=NULL) {
  305.          linked_char *next;
  306.        strcat(retbuf," may be made using the \nfollowing ingredients:\n");
  307.            for (next=formula->ingred; next!=NULL; next=next->next) { 
  308.                   strcat(retbuf,next->name); strcat(retbuf,"\n");
  309.        }
  310.         } else  
  311.        LOG(llevError,"formula_msg() no ingredient list for object %s of %s",
  312.          op_name,formula->title);
  313.   } else
  314.     strcat(retbuf," <indescipherable text>\n");
  315.  
  316. #ifdef BOOK_MSG_DEBUG
  317.   LOG(llevDebug,"\n formula_msg() created strng: %d\n",strlen(retbuf));
  318.   fprintf(logfile," MADE THIS:\n%s\n",retbuf);
  319. #endif
  320.  
  321.   return retbuf;
  322. }
  323. #endif
  324.  
  325. /* mon_info_msg() - generate a message detailing the properties 
  326.  * of a randomly selected monster.
  327.  */
  328.  
  329. char * mon_info_msg (int level, int booksize) {
  330.   static char retbuf[BOOK_BUF];
  331.   char tmpbuf[HUGE_BUF];
  332.   object *tmp;
  333.  
  334.   /*preamble */
  335.   strcpy(retbuf,"This beastuary contains:");
  336.  
  337.   /* lets print info on as many monsters as will fit in our 
  338.    * document. 
  339.    */
  340.   while((tmp=get_random_mon(level*3))!=NULL) { 
  341.  
  342.       /* monster description */
  343.       sprintf(tmpbuf,"\n---\n%s",mon_desc(tmp));
  344.  
  345.       if(!book_overflow(retbuf,tmpbuf,booksize)) 
  346.             strcat(retbuf,tmpbuf);
  347.       else break;
  348.   }
  349.  
  350. #ifdef BOOK_MSG_DEBUG
  351.   LOG(llevDebug,"\n mon_info_msg() created strng: %d\n",strlen(retbuf));
  352.   fprintf(logfile," MADE THIS:\n%s\n",retbuf);
  353. #endif
  354.  
  355.   return retbuf;
  356. }
  357.  
  358. char * mon_desc ( object *mon ) {
  359.   static char retbuf[HUGE_BUF];
  360.  
  361.   sprintf(retbuf," *** %s ***\n",mon->name);
  362.   strcat(retbuf,describe_item(mon));
  363.  
  364.   return retbuf;
  365. }
  366.  
  367. /* get_random_mon() - returns a random monster slected from linked 
  368.  * list of all monsters in the current game. If level is non-zero,
  369.  * then only monsters greater than that level will be returned.
  370.  */ 
  371.  
  372. object *get_random_mon ( int level ) {
  373.   objectlink *mon=first_mon_info;
  374.   int i=0,monnr;
  375.  
  376.   /* safety check.  Problem w/ init_mon_info list? */
  377.   if(!nrofmon||!mon) return (object *) NULL; 
  378.  
  379.   /* lets get a random monster from the mon_info linked list */
  380.   monnr = RANDOM()%nrofmon;
  381.   do {
  382.     mon = mon->next;
  383.     i++;
  384.   } while (i<monnr);
  385.  
  386.   /* now, we only print info on monsters w/ appropriate level */ 
  387.   if(level>0) {
  388.      int passed_once = 0;
  389.      while (mon->ob->level>level) 
  390.         if(mon->next) 
  391.           mon = mon->next; 
  392.         else if(!passed_once) { 
  393.           mon = first_mon_info; 
  394.       passed_once = 1;
  395.     } else {
  396.       LOG(llevError,"get_random_mon() couldnt return monster for level %d\n",
  397.         level);
  398.       return (object *) NULL;
  399.     } 
  400.   }
  401.  
  402.   return mon->ob;
  403. }
  404.  
  405. /* init_mon_info() - creates the linked list of pointers to 
  406.  * monster archetype objects if not called previously
  407.  */ 
  408.  
  409. void init_mon_info ( void ) {
  410.   archetype *at;
  411.   static int did_init_mon_info;
  412.  
  413.   if(!did_init_mon_info) did_init_mon_info=1;
  414.   else return;
  415.  
  416.   for(at=first_archetype;at!=NULL;at=at->next) {
  417.     if (QUERY_FLAG(&at->clone,FLAG_MONSTER)&&
  418.      (!QUERY_FLAG(&at->clone,FLAG_CHANGING)
  419.        ||QUERY_FLAG(&at->clone,FLAG_UNAGGRESSIVE))
  420.     ) {
  421.       objectlink *mon = (objectlink *) malloc(sizeof(objectlink));
  422.  
  423.     mon->ob = &at->clone;
  424.     mon->id = nrofmon;
  425.     if(first_mon_info)
  426.        mon->next = first_mon_info;
  427.     first_mon_info = mon;
  428.     nrofmon++;
  429.     }
  430.   }
  431.   LOG(llevDebug,"init_mon_info() got %d monsters\n",nrofmon);
  432. }
  433.  
  434. /* spellpath_msg() - generate a message detailing the member
  435.  * spells/prayers (and some of their properties) belonging to 
  436.  * a given spellpath. 
  437.  */ 
  438.  
  439. char * spellpath_msg (int level, int booksize) {
  440.   static char retbuf[BOOK_BUF];
  441.   char tmpbuf[BOOK_BUF];
  442.   int path=(RANDOM()%(NRSPELLPATHS+1)-1),prayers=RANDOM()%2;
  443.   int i=0,did_first_sp=0;  
  444.   uint32 pnum = (path==-1) ? PATH_NULL : spellpathdef[path];
  445.  
  446.   /* Preamble */
  447.   sprintf(retbuf,"Herein are detailed the names of %s\n",
  448.     !(prayers) ? "spells" : "prayers");
  449.   if(path==-1) 
  450.         strcat(retbuf,"having no known spell path.\n");
  451.   else    
  452.         sprintf(retbuf,"%sbelonging to the path of %s:\n",retbuf,
  453.         spellpathnames[path]);
  454.  
  455.   /* Now go through the entire list of spells. Add appropriate spells
  456.    * in our message buffer */
  457.  
  458.   do {
  459.     if((spells[i].books||prayers)&&spells[i].cleric==prayers
  460.     &&(pnum&spells[i].path)) {
  461.       /* book level determines max spell level to show 
  462.        * thus higher level books are more comprehensive */ 
  463.       if(spells[i].level>(level*3)) {
  464.          i++;
  465.          continue; 
  466.       }
  467.       strcpy(tmpbuf,spells[i].name);
  468.  
  469.       if(book_overflow(retbuf,tmpbuf,booksize))
  470.          break;
  471.       else { 
  472.              if(did_first_sp) strcat(retbuf,",\n");
  473.          did_first_sp=1;
  474.              strcat(retbuf,tmpbuf);
  475.       }
  476.     }
  477.     i++;
  478.   } while(i<NROFREALSPELLS);
  479.  
  480.   /* Geez, no spells were generated. */
  481.   if(!did_first_sp) 
  482.     if(RANDOM()%4) /* usually, lets make a recursive call... */
  483.        sprintf(retbuf, spellpath_msg(level,booksize));
  484.     else /* give up, cause knowning no spells exist for path is info too. */
  485.        strcat(retbuf,"\n - no known spells exist -\n");
  486.   else { 
  487. #ifdef BOOK_MSG_DEBUG
  488.      LOG(llevDebug,"\n spellpath_msg() created strng: %d\n",strlen(retbuf));
  489.      fprintf(logfile," MADE THIS: path=%d pray=%d\n%s\n",path,prayers,retbuf);
  490. #endif
  491.      strcat(retbuf,"\n");
  492.   }
  493.   return retbuf;
  494. }
  495.  
  496. /* artifact_msg() - generate a message detailing the properties
  497.  * of 1-6 artifacts drawn sequentially from the artifact list.
  498.  */
  499.  
  500. char *artifact_msg (int level, int booksize) {
  501.   artifactlist *al=NULL;
  502.   artifact *art;
  503.   int chance,i,type,index;
  504.   int book_entries=level>5?RANDOM()%3+RANDOM()%3+2:RANDOM()%level+1;
  505.   char *ch, name[MAX_BUF],buf[BOOK_BUF],sbuf[MAX_BUF];
  506.   static char retbuf[BOOK_BUF];
  507.   object *tmp=NULL;
  508.  
  509.   /* values greater than 5 create msg buffers that are too big! */
  510.   if(book_entries>5) book_entries=5;
  511.  
  512.   /* lets determine what kind of artifact type randomly.
  513.    * Right now legal artifacts only come from those listed
  514.    * in art_name_array. Also, we check to be sure an artifactlist
  515.    * for that type exists!
  516.    */
  517.   do {
  518.      index = RANDOM()%(sizeof(art_name_array)/sizeof(arttypename));
  519.      type=art_name_array[index].type;
  520.      al = find_artifactlist(type);
  521.   } while(al==NULL);
  522.  
  523.   /* There is no reason to start on the artifact list at the begining. Lets
  524.    * take our starting position randomly... */
  525.   art=al->items;
  526.   for(i=RANDOM()%level+RANDOM()%2+1;i>0;i--) {
  527.         if(art==NULL) art=al->items; /* hmm, out of stuff, loop back around */
  528.         art=art->next;
  529.   }
  530.  
  531.   /* the base 'generic' name for our artifact */
  532.   sprintf(name,art_name_array[index].name);
  533.  
  534.   /* Ok, lets print out the contents */
  535.   sprintf(retbuf,"Herein %s detailed %s...\n",book_entries>1?"are":"is",
  536.         book_entries>1?"some artifacts":"an artifact");
  537.  
  538.   /* artifact msg attributes loop. Lets keep adding entries to the 'book'
  539.    * as long as we have space up to the allowed max # (book_entires) 
  540.    */
  541.   while(book_entries>0){
  542.  
  543.     if(art==NULL) art=al->items;
  544.  
  545.     /* separator of items */
  546.     strcpy(buf,"--- \n");
  547.  
  548.     /* Name */
  549.     if (art->allowed!=NULL&&strcmp(art->allowed->name,"All")) {
  550.         linked_char *temp,*next=art->allowed;
  551.         do {
  552.           temp=next;
  553.           next=next->next;
  554.         } while ((next!=(linked_char *) NULL)&&!RANDOM()%2);
  555.         sprintf(buf,"%s A %s of %s",buf,temp->name,art->item->name);
  556.     }
  557.     else /* default name is used */
  558.         sprintf(buf,"%s The %s of %s",buf,name,art->item->name);
  559.  
  560.     /* chance of finding */
  561.     chance = 100 * ((float) art->chance/al->total_chance);
  562.     if(chance>=20) sprintf(sbuf,"an uncommon");
  563.     else if(chance>=10) sprintf(sbuf,"an unusual");
  564.     else if(chance>=5) sprintf(sbuf,"a rare");
  565.     else sprintf(sbuf,"a very rare");
  566.     sprintf(buf,"%s is %s\n",buf,sbuf);
  567.  
  568.     /* value of artifact */
  569.     sprintf(buf,"%s item with a value that is %d times normal.\n",
  570.         buf,art->item->value);
  571.  
  572.     /* include the message about the artifact, if exists, and book
  573.      * level is kinda high */
  574.     if(art->item->msg&&(RANDOM()%4+1)<level&&
  575.         !((strlen(art->item->msg)+strlen(buf))>BOOK_BUF))
  576.           sprintf(buf,"%s %s",buf,art->item->msg);
  577.  
  578.     /* properties of the artifact */
  579.     tmp=get_object();
  580.     add_abilities(tmp,art->item);
  581.     tmp->type = type;
  582.     SET_FLAG(tmp,FLAG_IDENTIFIED);
  583.     if((ch=describe_item(tmp))!=NULL&&strlen(ch)>1)
  584.         sprintf(buf,"%s Properties of this artifact include: \n %s \n",
  585.             buf,ch);
  586.  
  587.     /* add the buf if it will fit */
  588.     if(!book_overflow(retbuf,buf,booksize)) 
  589.            strcat(retbuf,buf);
  590.     else break; 
  591.  
  592.     art=art->next;
  593.     book_entries--;
  594.   }
  595.     
  596. #ifdef BOOK_MSG_DEBUG
  597.   LOG(llevDebug,"artifact_msg() created strng: %d\n",strlen(retbuf));
  598.   fprintf(logfile," MADE THIS:\n%s",retbuf);
  599. #endif
  600.   return retbuf;
  601. }   
  602.  
  603. /* arttype_has_name() returns the array value if the artifact is
  604.  * listed in art_name_array */
  605.  
  606. int arttype_has_name (int value) {
  607.   int i,number=sizeof(art_name_array)/sizeof(arttypename);
  608.  
  609.   for(i=0;i<number;i++)
  610.         if(art_name_array[i].type==value) return i;
  611.  
  612.   return -1;
  613. }
  614.  
  615. /* god_info_msg() - generate a message detailing the properties
  616.  * of a random god. Used by the book hack. b.t.
  617.  */
  618.  
  619. char *god_info_msg (int level, int booksize) {
  620.   static char retbuf[BOOK_BUF];
  621.   char *name=NULL, buf[BOOK_BUF];
  622.   int i,introlen;
  623.   int godnr=RANDOM()%NROFGODS; /* get a random god to 'profile' */
  624.  
  625.   name=Gods[godnr].name;
  626.   if(name==NULL) return (char *) NULL; /* oops, problems...*/
  627.  
  628.   /* preamble..*/
  629.   sprintf(retbuf,"This document contains knowledge concerning\n");
  630.   sprintf(retbuf,"%sthe diety %s",retbuf,name);
  631.  
  632.   /* Always have as default information the god's descriptive terms. */
  633.   if(nstrtok(Gods[godnr].desc,",")>0) {
  634.      strcat(retbuf,", known as");
  635.      strcat(retbuf,strtoktolin(Gods[godnr].desc,","));
  636.   } else
  637.      strcat(retbuf,"...");
  638.  
  639.   strcat(retbuf,"\n ---\n");
  640.   introlen = strlen(retbuf); /* so we will know if no new info is added later */
  641.  
  642.   /* Information about the god is random, and based on the level of the
  643.    * 'book'. Probably there is a more intellegent way to implement
  644.    * this ...
  645.    */
  646.  
  647.   while(level>0) {
  648.         sprintf(buf," ");
  649.         if(level==2&&RANDOM()%2) { /* enemy god */
  650.             char *enemy=Gods[godnr].enemy;
  651.             if(enemy) sprintf(buf,"The gods %s and %s are enemies.\n ---\n",
  652.                 name,enemy);
  653.         }
  654.         if(level==3&&RANDOM()%2) { /* enemy race, what the god's holy word effects */
  655.             char *enemy=Gods[godnr].enemy_race;
  656.             if(enemy&&!(Gods[godnr].path_denied&PATH_TURNING))
  657.                if((i=nstrtok(enemy,","))>0) {
  658.                     char tmpbuf[MAX_BUF];
  659.                     sprintf(buf,"The holy words of %s have the power to\n",name);
  660.                     strcat(buf,"slay creatures belonging to the ");
  661.                     if(i>1)
  662.                         sprintf(tmpbuf,"following \n races:%s",
  663.                           strtoktolin(enemy,","));
  664.                     else
  665.                         sprintf(tmpbuf,"race of%s",strtoktolin(enemy,","));
  666.                     sprintf(buf,"%s%s\n ---\n",buf,tmpbuf);
  667.                }
  668.         }
  669.         if(level==4&&RANDOM()%2) { /* Priest of god gets these protect,vulnerable... */
  670.                 int has_effect=0,tmpvar;
  671.                 char tmpbuf[MAX_BUF];
  672.                 sprintf(tmpbuf,"%s has a potent aura which is extended\n"
  673.                         ,name);
  674.                 strcat(tmpbuf,"faithful priests. The effects of this aura include:\n");
  675.                 if((tmpvar=Gods[godnr].protected)) {
  676.                         has_effect = 1;
  677.                         DESCRIBE_ABILITY(tmpbuf, tmpvar, "Protected");
  678.                 }
  679.                 if(strlen(tmpbuf)>38) sprintf(tmpbuf,"%s\n",tmpbuf);
  680.                 if((tmpvar=Gods[godnr].vulnerable)) {
  681.                         has_effect = 1;
  682.                         DESCRIBE_ABILITY(tmpbuf, tmpvar, "Vulnerable");
  683.                 }
  684.                 if(has_effect) {
  685.                         strcat(buf,tmpbuf);
  686.                         strcat(buf,"\n ---\n");
  687.                 } else
  688.                         sprintf(buf," ");
  689.         }
  690.         if(level==5&&RANDOM()%2) { /* aligned race, summoning  */
  691.             char *race=Gods[godnr].aligned_race;
  692.             if(race&&!(Gods[godnr].path_denied&PATH_SUMMON))
  693.                if((i=nstrtok(race,","))>0) {
  694.                     char tmpbuf[MAX_BUF];
  695.                     sprintf(buf,"Creatures sacred to %s include the \n",name);
  696.                     if(i>1)
  697.                         sprintf(tmpbuf,"following \n races:%s",
  698.                           strtoktolin(race,","));
  699.                     else
  700.                         sprintf(tmpbuf,"race of%s",strtoktolin(race,","));
  701.                     sprintf(buf,"%s%s\n ---\n",buf,tmpbuf);
  702.                }
  703.         }
  704.         if(level==6&&RANDOM()%2) { /* blessing,curse properties of the god */
  705.                 int has_effect=0,tmpvar;
  706.                 char tmpbuf[MAX_BUF];
  707.                 sprintf(tmpbuf,"\n");
  708.                 sprintf(tmpbuf,"The priests of %s are known to be able to \n"
  709.                         ,name);
  710.                 if((tmpvar=Gods[godnr].protected)) {
  711.                         has_effect = 1;
  712.                         strcat(tmpbuf,"bestow a blessing which makes the recipient\n");
  713.                         DESCRIBE_ABILITY(tmpbuf, tmpvar, "Protected");
  714.                 }
  715.                 if((tmpvar=Gods[godnr].vulnerable)) {
  716.                         strcat(tmpbuf,"\n");
  717.                         if(has_effect) strcat(tmpbuf,"and ");
  718.                         else has_effect = 1;
  719.                         strcat(tmpbuf,"lay a curse which makes the recipient\n");
  720.                         DESCRIBE_ABILITY(tmpbuf, tmpvar, "Vulnerable");
  721.                 }
  722.                 if(has_effect) {
  723.                         strcat(buf,tmpbuf);
  724.                         strcat(buf,"\n ---\n");
  725.                 } else
  726.                         sprintf(buf," ");
  727.         }
  728.         if(level==8&&RANDOM()%2) {  /* immunity, holy possession */
  729.                 int has_effect=0,tmpvar;
  730.                 char tmpbuf[MAX_BUF];
  731.                 sprintf(tmpbuf,"\n");
  732.                 sprintf(tmpbuf,"The priests of %s are known to make cast a mighty \n"
  733.                         ,name);
  734.                 if((tmpvar=Gods[godnr].immune)) {
  735.                         has_effect = 1;
  736.                         strcat(tmpbuf,"prayer of possession which gives the recipient\n");
  737.                         DESCRIBE_ABILITY(tmpbuf, tmpvar, "Immunity");
  738.                 }
  739.                 if(has_effect) {
  740.                         strcat(buf,tmpbuf);
  741.                         strcat(buf,"\n ---\n");
  742.                 } else
  743.                         sprintf(buf," ");
  744.         }
  745.         if(level==12&&RANDOM()%2) { /* spell paths */
  746.                 int has_effect=0,tmpvar;
  747.                 char tmpbuf[MAX_BUF];
  748.                 sprintf(tmpbuf,"\n");
  749.                 sprintf(tmpbuf,"It is rarely known fact that the priests of %s\n"
  750.                         ,name);
  751.                 strcat(tmpbuf,"are mystically transformed. Effects of this include:\n");                if((tmpvar=Gods[godnr].path_attuned)) {
  752.                         has_effect = 1;
  753.                         DESCRIBE_PATH(tmpbuf, tmpvar, "Attuned");
  754.                 }
  755.                 if((tmpvar=Gods[godnr].path_repelled)) {
  756.                         has_effect = 1;
  757.                         DESCRIBE_PATH(tmpbuf, tmpvar, "Repelled");
  758.                 }
  759.                 if((tmpvar=Gods[godnr].path_denied)) {
  760.                         has_effect = 1;
  761.                         DESCRIBE_PATH(tmpbuf, tmpvar, "Denied");
  762.                 }
  763.                 if(has_effect) {
  764.                         strcat(buf,tmpbuf);
  765.                         strcat(buf,"\n ---\n");
  766.                 } else
  767.                         sprintf(buf," ");
  768.         }
  769.  
  770.         /* check to be sure new buffer size dont exceed either
  771.          * the maximum buffer size, or the 'natural' size of the
  772.          * book...
  773.          */
  774.     if(book_overflow(retbuf,buf,booksize)) 
  775.         break;
  776.         else if(strlen(buf)>1) strcat(retbuf,buf);
  777.         level--;
  778.   }
  779.   if(strlen(retbuf)==introlen) { /* we got no information beyond the preamble! */
  780.         strcat(retbuf," [Unfortunately the rest of the information is\n");
  781.         strcat(retbuf,"  hopelessly garbled!]\n ---\n");
  782.   }
  783. #ifdef BOOK_MSG_DEBUG
  784.   LOG(llevDebug,"\n god_info_msg() created strng: %d\n",strlen(retbuf));
  785.   fprintf(logfile," MADE THIS:\n%s",retbuf);
  786. #endif
  787.   return retbuf;
  788. }
  789.  
  790. int book_overflow(char *buf1, char *buf2, int booksize) {
  791.  
  792.   if( buf_overflow(buf1,buf2,BOOK_BUF-2) /* 2 less so always room for trailing \n */ 
  793.      || buf_overflow(buf1,buf2,booksize))
  794.     return 1;
  795.   return 0;
  796. }
  797.  
  798. /* HANDMADE STRING FUNCTIONS.., perhaps these belong in another file 
  799.  * (shstr.c ?), but the quantity BOOK_BUF will need to be defined. */
  800.  
  801. /* buf_overflow() - we don't want to exceed the buffer size of 
  802.  * buf1 by adding on buf2! Returns true if overflow will occur.
  803.  */
  804.  
  805. int buf_overflow(char *buf1, char *buf2, int bufsize) {
  806.   int len1=0,len2=0;
  807.   
  808.   if(buf1) len1=strlen(buf1); 
  809.   if(buf2) len2=strlen(buf2); 
  810.   if((len1+len2)>=bufsize) return 1;
  811.   return 0;
  812. }
  813.  
  814. /* nstrtok() - simple routine to return the number of list
  815.  * items in buf1 as separated by the value of buf2
  816.  */
  817.  
  818. int nstrtok (char *buf1, char *buf2) {
  819.   char *tbuf,sbuf[12],buf[MAX_BUF];
  820.   int number=0;
  821.  
  822.   if(!buf1||!buf2) return 0;
  823.   sprintf(buf,"%s",buf1);
  824.   sprintf(sbuf,"%s",buf2);
  825.   tbuf=strtok(buf,sbuf);
  826.   while(tbuf) {
  827.        number++;
  828.        tbuf = strtok(NULL,sbuf);
  829.   }
  830.   return number;
  831. }
  832.  
  833. /* strtoktolin() - takes a string in buf1 and separates it into
  834.  * a list of strings delimited by buf2. Then returns a comma
  835.  * separated string w/ decent punctuation.
  836.  */
  837.  
  838. char *strtoktolin (char *buf1, char *buf2) {
  839.   int maxi, i = nstrtok(buf1,buf2);
  840.   char *tbuf, buf[MAX_BUF], sbuf[12];
  841.   static char rbuf[BOOK_BUF];
  842.  
  843.   maxi = i;
  844.   sprintf(buf,"%s",buf1);
  845.   sprintf(sbuf,"%s",buf2);
  846.   sprintf(rbuf," ");
  847.   tbuf = strtok(buf,sbuf);
  848.   while(tbuf&&i>0) {
  849.         strcat(rbuf,tbuf);
  850.         i--;
  851.         if(i==1&&maxi>1) strcat(rbuf," and ");
  852.         else if(i>0&&maxi>1) strcat(rbuf,", ");
  853.         else strcat(rbuf,".");
  854.         tbuf = strtok(NULL,sbuf);
  855.   }
  856.   return (char *) rbuf;
  857. }
  858.